from flask import Flask, render_template, session, request, jsonify, send_from_directory
from flask_socketio import SocketIO, emit, join_room, leave_room
import random
import json
import time
import sqlite3
from datetime import datetime

from conf import *

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)


# 游戏数据库初始化
def init_db():
    conn = sqlite3.connect('game.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS games
                 (id TEXT PRIMARY KEY, state TEXT, players TEXT, created_at TIMESTAMP)''')
    conn.commit()
    conn.close()

init_db()

# 游戏数据模型
class GameState:
    def __init__(self, game_id):
        self.game_id = game_id
        self.players = {}
        self.current_player = None
        self.phase = "lobby"  # lobby, build, serve, end
        self.turn = 0
        self.shop_types = SHOP_TYPES
        self.shop_list = random.sample(
            [item["id"]+"_1" for item in SHOP_TYPES] + [item["id"]+"_2" for item in SHOP_TYPES] + [item["id"]+"_3" for item in SHOP_TYPES],
            len(SHOP_TYPES) * 3
        ) # 随机生成商店列表
        self.customer_types = CUSTOMER_TYPES
        self.customer_list = random.sample(
            [[item["id"]+"_1", 0] for item in CUSTOMER_TYPES] + [[item["id"]+"_2", 0] for item in CUSTOMER_TYPES] + [[item["id"]+"_3", 0] for item in CUSTOMER_TYPES],
            len(CUSTOMER_TYPES) * 3
        ) # 随机生成顾客列表
        self.customer_num = 4 # 顾客队列数量
        self.menu_levels = MENU_LEVELS
        self.plot_cleaning_costs = CLEAN_COST  # 地块清理费用
        self.notice = ""
        
    def init_game(self):
        self.phase = "build"
        self.turn = 0
        self.current_player = list(self.players.keys())[0]
        
        # 初始化玩家数据
        for player_id in list(self.players.keys()):
            player_name = self.players[player_id]["name"]
                
            self.players[player_id] = {
                "id": player_id,
                "name": player_name,
                "money": 30 + list(self.players.keys()).index(player_id), # 根据玩家顺序分配初始资金
                "shops": [],
                "plots": ["empty"] * 8,  # 初始化8块空地
                # "menu_level": 1,
                "menu": random.sample([1]*6 + [2]*2, 8),  # 初始六张四品两张三品菜
                "kitchen": 0, # 初始后厨菜品数量
            }
    
    def add_player(self, player_id, name):
        self.players[player_id] = {"name": name}

    def get_next_player(self, player_id):
        players = list(self.players.keys())
        return players[(players.index(player_id)+1)%len(players)]
    
    def to_dict(self, for_player=None):
        """返回游戏状态，可选指定玩家视角"""
        base_data = {
            "game_id": self.game_id,
            "current_player": self.current_player,
            "phase": self.phase,
            "turn": self.turn,
            "shop_types": self.shop_types,
            "shop_list": self.shop_list,
            "customer_types": self.customer_types,
            "customer_list": self.customer_list,
            "customer_num": self.customer_num,
            "menu_levels": self.menu_levels, 
            "notice": self.notice
        }
        
        # 大厅阶段 - 返回所有玩家名称
        if self.phase == "lobby":
            players_data = {}
            for player_id, player in self.players.items():
                if isinstance(player, dict) and "name" in player:
                    players_data[player_id] = {"name": player["name"]}
                else:
                    # 处理旧格式数据
                    players_data[player_id] = {"name": player}
            base_data["players"] = players_data
            return base_data
        
        # 游戏进行阶段
        if for_player is None:
            # 返回完整状态
            base_data["players"] = self.players
        else:
            # 给指定玩家返回定制状态
            base_data["players"] = {}
            for player_id, player in self.players.items():
                if player_id == for_player:
                    # 给当前玩家返回完整信息
                    base_data["players"][player_id] = player
                else:
                    # 给其他玩家返回基本信息
                    base_data["players"][player_id] = {
                        "name": player["name"],
                        "money": player["money"],
                        "shops_count": len(player["shops"]),
                        "plots_cleared": sum(1 for plot in player["plots"] if plot != "empty"),
                        "menu_level": player["menu_level"]
                    }
        
        return base_data
    
    def save_to_db(self):
        conn = sqlite3.connect('game.db')
        c = conn.cursor()
        state_json = json.dumps(self.to_dict())
        players_json = json.dumps(list(self.players.keys()))
        c.execute('''INSERT OR REPLACE INTO games (id, state, players, created_at)
                     VALUES (?, ?, ?, ?)''', 
                 (self.game_id, state_json, players_json, datetime.now()))
        conn.commit()
        conn.close()
    
    @classmethod
    def load_from_db(cls, game_id):
        conn = sqlite3.connect('game.db')
        c = conn.cursor()
        c.execute("SELECT state FROM games WHERE id = ?", (game_id,))
        row = c.fetchone()
        conn.close()
        
        if row:
            state_data = json.loads(row[0])
            game = cls(game_id)
            game.players = state_data["players"]
            game.current_player = state_data["current_player"]
            game.phase = state_data["phase"]
            game.turn = state_data["turn"]
            
            # 如果从数据库加载的是大厅状态，确保玩家数据格式正确
            if game.phase == "lobby":
                for player_id, data in game.players.items():
                    if "name" not in data:
                        # 修复数据格式
                        game.players[player_id] = {"name": data}
            
            return game
        return None

# 游戏管理
games = {}

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/game/<game_id>/player/<player_id>')
def game_page(game_id, player_id):
    return render_template('game.html', game_id=game_id, player_id=player_id)

@app.route('/get_image/<mood>')
def get_image(mood):
    # 返回对应图片（支持自定义文件名规则）
    filename = next(s["icon"] for s in SHOP_TYPES if s["id"] == mood)
    return send_from_directory('static', filename)

@app.route('/create_game', methods=['POST'])
def create_game():
    data = request.json
    player_name = data['player_name']

    game_id = str(int(time.time()))
    games[game_id] = GameState(game_id)

    # 生成主机唯一玩家ID
    timestamp = str(int(time.time()))
    player_count = str(len(games[game_id].players))
    player_id = f"host_{player_count}_{timestamp}"
    
    # 添加玩家
    games[game_id].add_player(player_id, player_name)
    games[game_id].save_to_db()
    return jsonify({
        "player_id": player_id,
        "game_id": game_id
    })

@app.route('/join_game', methods=['POST'])
def join_game():
    data = request.json
    game_id = data['game_id']
    player_name = data['player_name']
    
    if game_id not in games:
        game = GameState.load_from_db(game_id)
        if game:
            games[game_id] = game
        else:
            return jsonify({"error": "Game not found"}), 404
    
    # 生成唯一玩家ID
    timestamp = str(int(time.time()))
    player_count = str(len(games[game_id].players))
    player_id = f"player_{player_count}_{timestamp}"
    
    # 添加玩家
    games[game_id].add_player(player_id, player_name)
    games[game_id].save_to_db()
    
    return jsonify({
        "player_id": player_id,
        "game_id": game_id
    })

@socketio.on('join')
def on_join(data):
    game_id = data['game_id']
    player_id = data['player_id']
    room = game_id
    
    join_room(room)
    session['room'] = room
    session['player_id'] = player_id
    
    if game_id in games:
        # 发送更新给新加入的玩家
        emit('update_game', games[game_id].to_dict(for_player=player_id), room=player_id)
        
        # 向房间内所有玩家广播更新
        emit('update_game', games[game_id].to_dict(), room=room)

@socketio.on('start_game')
def on_start_game(data):
    game_id = data['game_id']
    if game_id in games:
        print(f"【游戏启动】游戏ID: {game_id}")
        print(f"【玩家列表】: {list(games[game_id].players.keys())}")
        
        games[game_id].init_game()
        games[game_id].save_to_db()
        
        print(f"【初始化后玩家数据】: {games[game_id].players}")
        
        # 向所有玩家广播游戏开始
        emit('update_game', games[game_id].to_dict(), room=game_id)

@socketio.on('buy_menu')
def on_buy_menu(data):
    game_id = data['game_id']
    menu_level = data['menu_level']
    player_id = session['player_id']
    
    if game_id in games:
        game = games[game_id]
        if game.phase == "build" and game.current_player == player_id:
            player = game.players[player_id]
            current_menu = next(s for s in game.menu_levels if s["level"] == menu_level)
            if current_menu["total"] > 0 and player["money"] >= current_menu["cost"]:
                player["menu"].insert(0, current_menu["level"])
                player["kitchen"] += 1
                player["money"] -= current_menu["cost"]
                current_menu["total"] -= 1
                game.save_to_db()
                emit('update_game', game.to_dict(), room=game_id)

@socketio.on('remove_menu')
def on_remove_menu(data):
    game_id = data['game_id']
    menu_level = data['menu_level']
    player_id = session['player_id']
    
    if game_id in games:
        game = games[game_id]
        if game.phase == "build" and game.current_player == player_id:
            player = game.players[player_id]
            current_menu = next(s for s in game.menu_levels if s["level"] == menu_level)
            
            if menu_level in player["menu"][:player["kitchen"]+1] and player["money"] >= 3 and len(player["menu"]) >= 7: 
                player["menu"].remove(menu_level)
                player["kitchen"] -= 1
                player["money"] -= 3
                current_menu["total"] += 1
                game.save_to_db()
                emit('update_game', game.to_dict(), room=game_id)

@socketio.on('finish_serve')
def on_finish_serve(data):
    game_id = data['game_id']
    player_id = session['player_id']
    
    if game_id in games:
        game = games[game_id]
        if game.current_player == player_id:
            game.current_player = game.get_next_player(player_id)
            game.phase = "build"
            game.save_to_db()
            emit('update_game', game.to_dict(), room=game_id)

@socketio.on('change_phase')
def on_change_phase(data):
    game_id = data['game_id']
    player_id = session['player_id']
    phase = data['phase']
    
    if game_id in games:
        game = games[game_id]
        if game.current_player == player_id:
            game.phase = phase
            game.save_to_db()
            emit('update_game', game.to_dict(), room=game_id)

@socketio.on('serve_customer')
def on_serve_customer(data):
    game_id = data['game_id']
    player_id = session['player_id']
    customer_id = data['customer_id']
    
    if game_id in games:
        game = games[game_id]
        if game.phase == "serve" and game.current_player == player_id:
            player = game.players[player_id]
            customer = next(s for s in game.customer_types if s["id"] == customer_id.split("_")[0])
            
            # 基础收入
            income = 0
            for i in range(customer["income"]):
                # 如果到了菜单长度，刷新菜单
                if i+player["kitchen"] == len(player["menu"]):
                    random.shuffle(player["menu"])
                income += player["menu"][(i+player["kitchen"])%len(player["menu"])]

            # 如果结束后到了菜单长度，刷新菜单
            if customer["income"]+player["kitchen"] == len(player["menu"]):
                random.shuffle(player["menu"])

            # 更新后厨序号
            player["kitchen"] = (customer["income"]+player["kitchen"])%len(player["menu"])

            # 跳过客人支出
            outcome = 0
            stay_bonus = 0
            for s in game.customer_list:
                if s[0] == customer_id:
                    stay_bonus = s[1]
                    break
                s[1] += 1
                outcome += 1
            
            # 店铺加成
            shop_bonus = 0
            for i, shop in enumerate(player["shops"]):
                if player["plots"][i] == "built":
                    shop_type = next(s for s in game.shop_types if s["id"] == shop["type"])
                    if shop_type["id"] in customer["shop"]:
                        shop_bonus += shop_type["income"]
            
            total_income = stay_bonus + income - outcome + shop_bonus
            player["money"] += total_income
            
            game.customer_list.remove([customer_id, stay_bonus])

            # 进入结束阶段
            game.phase = "end"
            game.save_to_db()
            
            result = {
                "customer": customer,
                "income": income,
                "stay_bonus": stay_bonus,
                "outcome": outcome,
                "stay_outcome": outcome,
                "shop_bonus": shop_bonus,
                "total_income": total_income
            }
            
            emit('update_game', game.to_dict(), room=game_id)
            emit('serve_result', result, room=game_id)

# 清理地块事件
@socketio.on('clean_plot')
def on_clean_plot(data):
    game_id = data['game_id']
    plot_index = data['plot_index']
    shop_type = data['shop_type' ]
    player_id = session['player_id']
    
    if game_id in games:
        game = games[game_id]
        if game.phase == "build" and game.current_player == player_id:
            player = game.players[player_id]
            
            # 确保地块索引有效
            if plot_index < 0 or plot_index >= len(player["plots"]):
                emit('game_message', {"message": "无效的地块索引！"}, room=player_id)
                return
                
            # 检查地块状态
            if player["plots"][plot_index] != "empty":
                emit('game_message', {"message": "该地块已经清理过了！"}, room=player_id)
                return
                
            # 获取清理费用
            cleaning_cost = game.plot_cleaning_costs[plot_index]
            shop = next(s for s in game.shop_types if s["id"] == shop_type.split("_")[0])
            
            if player["money"] >= cleaning_cost:
                player["money"] -= cleaning_cost
                player["plots"][plot_index] = "cleared"  # 标记为已清理
                
                # 从shop队列清理掉
                game.shop_list.remove(shop_type)

                # 建造店铺
                player["shops"].append({
                    "type": shop["id"],
                    "name": shop["name"],
                    "income": shop["income"],
                    "plot": plot_index,  # 记录店铺所在的地块
                    "built": False,
                    "cost": shop["cost"]
                })

                # 保存游戏状态
                game.save_to_db()
                
                # 发送更新
                emit('update_game', game.to_dict(), room=game_id)
                emit('game_message', {"message": f"成功清理地块 {plot_index+1}，花费 {cleaning_cost} 两白银"}, room=player_id)
            else:
                emit('game_message', {"message": f"白银不足！清理需要 {cleaning_cost} 两白银，你只有 {player['money']} 两"}, room=player_id)

# 建造店铺事件
@socketio.on('build_shop')
def on_build_shop(data):
    game_id = data['game_id']
    plot_index = data['plot_index']
    player_id = session['player_id']
    
    if game_id in games:
        game = games[game_id]
        if game.phase == "build" and game.current_player == player_id:
            player = game.players[player_id]
            
            # 确保地块索引有效
            if plot_index < 0 or plot_index >= len(player["plots"]):
                emit('game_message', {"message": "无效的地块索引！"}, room=player_id)
                return
                
            # 检查地块状态
            if player["plots"][plot_index] != "cleared":
                emit('game_message', {"message": "该地块尚未清理，无法建造！"}, room=player_id)
                return
                
            shop = player["shops"][plot_index]
            building_cost = shop["cost"]
            
            if player["money"] >= building_cost:
                player["money"] -= building_cost
                player["plots"][plot_index] = "built"  # 标记为已建造
                
                # 建造店铺
                shop["built"] = True

                # 检查胜利条件
                built_shop = [s for s in player["shops"] if s["built"] == True]
                if len(built_shop) >= 8 and player["money"] >= 50:
                    game.phase = "end"
                    game.save_to_db()
                    emit('game_end', {"winner": player_id, "name": player["name"]}, room=game_id)
                else:
                    # 保存游戏状态
                    game.save_to_db()
                    
                    # 发送更新
                    emit('update_game', game.to_dict(), room=game_id)
                    emit('game_message', {"message": f"成功建造 {shop['name']}，花费 {building_cost} 两白银"}, room=player_id)
            else:
                emit('game_message', {"message": f"白银不足！建造需要 {building_cost} 两白银，你只有 {player['money']} 两"}, room=player_id)

if __name__ == '__main__':
    socketio.run(app, debug=True, host='0.0.0.0', port=5000)